feat(memory): port memory manager and extraction to Python#2740
Conversation
Port the strands-ts memory module to strands-py: a MemoryManager plugin with search_memory/add_memory tools, pluggable MemoryStore backends, and background extraction (ExtractionCoordinator, ModelExtractor, invocation/interval triggers). Adapts the TS promise model to asyncio: gather(return_exceptions=True) for Promise.allSettled, per-store asyncio.Task chains for serialized saves, and a tracked background-task set. Adds an opt-in flush_on_invocation_end so extraction persists under the synchronous Agent(...) entry point, whose per-invocation event loop would otherwise cancel in-flight saves. Adds AggregateMemoryError to types/exceptions for Python 3.10-safe multi-store failure aggregation (ExceptionGroup is 3.11+).
|
Question — shipped store backend: This PR adds the Is a concrete store (and an integ test) following in a separate PR? If so, a one-line note in the description would set expectations. If this is meant to be usable on its own, shipping at least an in-memory store would make the feature self-contained and give the suite an end-to-end anchor beyond the unit-level fakes. |
|
Process note — API review label: This PR introduces a substantial new public API surface — a new top-level The PR description does an excellent job documenting use cases, signatures, and the asyncio deviation — that's exactly the proposer prep the doc asks for. Could you add the |
|
Assessment: Comment A clean, well-documented port. Tests pass (106), Review themes
Nicely structured, well-tested work — the whole-object equality assertions and case-for-case TS parity make the suite easy to trust. |
Move the _flatten_reasons helper into memory_manager.py (where the TS source defines it) and delete memory/_errors.py, which had no TypeScript counterpart. AggregateMemoryError remains in strands.types.exceptions.
Add flush_on_invocation_end to MemoryManagerConfig so the doc/typing aid matches the constructor, and document the intentional empty-stores divergence (mirrored from TS) between the tools and the programmatic search/add APIs. Addresses PR strands-agents#2740 review.
|
Assessment: Comment (approve — code is solid; design follow-ups are maintainer/author calls) Reviewed
Re-verified on Still open — but these are maintainer/author decisions, not code blockersThe substantive design questions from the review are tracked in-thread and don't block the port:
From my side the code is in good shape and all actionable review nits on this commit are addressed; the remaining items are design conversations for the team. |
Collapse over-explained docstrings to concise summaries, drop Args/Returns blocks for self-evident params, and shorten multi-line rationale comments to one line. No code changes.
|
Assessment: Comment (approve — pure documentation commit, no behavioral change) Reviewed I verified this is genuinely docs-only: I stripped all docstrings via AST from both The trims condense some genuinely verbose prose (e.g. the multi-paragraph "how it works in three pieces" module docstring) into tighter summaries, while preserving the key concepts a reader needs — the per-store high-water mark, the per-store task chain serialization, backoff/probe behavior, and the never-raises guarantee. This is a net readability win. Re-verified on No code concerns. Position unchanged — the code is in good shape; the remaining open items are the design conversations in @pgrayy's review thread. |
Remove class-enumerating module docstrings, self-evident Args/Returns blocks on coordinator helpers, and an implementation note, keeping only behavior callers cannot infer from signatures.
flush() also waits out saves that begin while it is waiting, a guarantee callers cannot infer from the signature.
|
Assessment: Comment (approve — one-line docstring restore, no behavioral change) Reviewed This restores the "also waits out saves that start while waiting" note on AST-strip confirms No concerns. Position unchanged. |
Description
Ports the
memorymodule from the TypeScript SDK (strands-ts/src/memory) to the Python SDK (strands-py). The module gives agents cross-session recall and persistence through aMemoryManagerplugin that manages pluggableMemoryStorebackends, exposessearch_memory/add_memorytools, and runs automatic background extraction that distills conversation turns into durable memory.This is a behavior-preserving port: the TypeScript test suite is the reference, and every
it(...)case has a Python counterpart. The notable design work is adapting the TS promise/event-loop model to Pythonasyncio.Public API — new package
strands.memory:Also adds
AggregateMemoryErrortostrands.types.exceptions— a Python 3.10-safe stand-in for JSAggregateError(ExceptionGroupis 3.11+) used to surface multi-store write failures with each underlying reason.Asyncio adaptation (key deviation from TS). TS relies on a long-lived event loop, so fire-and-forget background saves survive between turns. Python's synchronous
Agent(...)entry point runs each invocation in a fresh loop (asyncio.run), which cancels in-flight tasks on return. The port usesasyncio.gather(return_exceptions=True)forPromise.allSettled, per-storeasyncio.Taskchains for serialized saves, and a tracked background-task set. The opt-inflush_on_invocation_end(defaultFalse) registers anAfterInvocationEventhook that awaits pending writes before the per-invocation loop tears down; async callers owning a persistent loop can leave it off and callflush()at a shutdown boundary. This flag has no TS equivalent and exists solely to bridge the event-loop lifecycle difference.Scope. This PR ports
strands-ts/src/memory/only. Concrete store backends (e.g.BedrockKnowledgeBaseStore, which lives in the separatestrands-ts/src/vended-memory-stores/module) are intended as a follow-up PR; this change ships theMemoryManagermachinery and theMemoryStoreprotocol that those backends implement.Related Issues
N/A
Documentation PR
No new docs required; public classes are documented via docstrings.
Type of Change
New feature
Testing
How have you tested the change? Verify that the changes do not break functionality or introduce new warnings.
Ported the three TS test files (
memory-manager,extraction,model-extractor) as example-basedpytestsuites so coverage mirrors the TS suite case-for-case; runs green undertests/strands/memory. Adjacentplugins/toolssuites were run to confirm no regressions in plugin/tool discovery.hatch run prepareChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.